//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
namespace LargoCommon.Music
{
using LargoCommon.Interfaces;
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Text;
using System.Xml.Serialization;
///
/// Binary Structure.
///
[Serializable]
[XmlRoot]
public class BinaryStructure : GeneralOwner, IComparable, IGeneralStruct {
#region Fields
///
/// Bit Array.
///
private BitArray bitArray;
///
/// Structural Code.
///
private string structuralCode;
///
/// General system.
///
private GeneralSystem gsystem; //// readonly
/// Number of nonzero bits, number of rotations.
private byte level;
#endregion
#region Constructors
/// Initializes a new instance of the BinaryStructure class. Serializable.
public BinaryStructure() {
}
/// Initializes a new instance of the BinaryStructure class.
/// Abstract system.
/// Structural code.
public BinaryStructure(GeneralSystem givenSystem, string givenStructuralCode) {
Contract.Requires(givenSystem != null);
this.gsystem = givenSystem;
this.SetStructuralCode(givenStructuralCode);
this.DetermineLevel();
//// 2014/12 Time optimization
//// this.CheckInstance();
}
/// Initializes a new instance of the BinaryStructure class.
/// Abstract system.
/// Bit array.
public BinaryStructure(GeneralSystem givenSystem, BitArray givenBitArray) {
Contract.Requires(givenSystem != null);
this.gsystem = givenSystem;
this.bitArray = givenBitArray;
this.DetermineLevel();
//// 2014/12 Time optimization
//// this.CheckInstance();
}
/// Initializes a new instance of the BinaryStructure class.
/// Abstract system.
/// Number of structure.
public BinaryStructure(GeneralSystem givenSystem, long number) {
this.gsystem = givenSystem ?? throw new InvalidOperationException("G-system is null.");
this.DecimalNumber = number;
this.SetNumber(number);
this.DetermineLevel();
//// 2014/12 Time optimization
//// this.CheckInstance();
}
/// Initializes a new instance of the BinaryStructure class.
/// Binary structure.
public BinaryStructure(BinaryStructure structure) {
Contract.Requires(structure != null);
this.gsystem = structure.GSystem;
this.bitArray = (BitArray)structure.BitArray.Clone();
this.level = structure.Level;
//// 2014/12 Time optimization
//// this.CheckInstance();
}
#endregion
#region Properties
/// Gets BitArray.
/// Property description.
public BitArray BitArray {
get {
Contract.Ensures(Contract.Result() != null);
if (this.bitArray == null) {
throw new InvalidOperationException("Bit array is null.");
}
return this.bitArray;
}
}
/// Gets or sets Number.
/// Property description.
public long Number { get; set; }
/// Gets or sets DecimalNumber.
/// Property description.
public decimal DecimalNumber { get; set; }
/// Gets or sets abstract G-System.
/// Property description.
[XmlIgnore]
//// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Contracts", "Ensures")]
public GeneralSystem GSystem {
get {
Contract.Ensures(Contract.Result() != null);
Contract.Ensures(Contract.Result().Order > 0);
if (this.gsystem == null) {
throw new InvalidOperationException("G-system is null.");
}
return this.gsystem;
}
set => this.gsystem = value ?? throw new ArgumentException("Argument cannot be empty.", nameof(value));
}
/// Gets or sets modality.
/// Property description.
[XmlIgnore]
public IGeneralStruct Modality { get; set; }
/// Gets or sets level, i.e. number of ones in the structure.
/// Property description.
[XmlAttribute]
public byte Level {
get => this.level;
set {
this.level = value;
this.SetProperty(GenProperty.Level, this.level);
}
}
///
/// Gets or sets the occurrence - for statistical reasons (material,...). May be moved to properties...
///
///
/// The occurrence.
///
public int Occurrence { get; set; }
///
/// Gets or sets the class code.
///
///
/// The class code.
///
public string ClassCode { get; set; }
#endregion
#region Schemas
/// Gets positions of nonzero bits.
/// Property description.
[XmlIgnore]
public Collection BitPlaces {
get {
Contract.Ensures(Contract.Result>() != null);
var places = new Collection();
var order = this.GSystem.Order;
for (byte e = 0; e < order; e++) {
if (this.IsOn(e)) {
places.Add(e);
}
}
return places;
}
}
/// Gets distances of nonzero bits.
/// Property description.
[XmlIgnore]
public Collection BitDistances {
get {
var places = this.BitPlaces;
var distances = new Collection();
var order = this.GSystem.Order;
if (this.Level > 1) {
byte p = 0, r = 0;
var lastL = (byte)(this.Level - 1);
for (byte lev = 0; lev < lastL; lev++) {
if (lev + 1 < places.Count) {
p = places[lev]; //// p = this.PlaceAtLevel(lev);
r = places[lev + 1]; //// r = this.PlaceAtLevel((byte)(lev + 1));
}
distances.Add(this.GSystem.FormalLength(r - p)); //// + order
}
if (lastL < places.Count) {
p = places[lastL]; //// p = this.PlaceAtLevel(lastL);
}
if (places.Count > 0) {
r = places[0]; //// r = this.PlaceAtLevel(0);
}
distances.Add(this.GSystem.FormalLength(r - p)); //// + order
}
else {
distances.Add(order);
}
return distances;
}
}
///
/// Gets the number.
///
/// Returns value.
public long GetNumber {
get {
//// Contract.Requires(this.BitArray != null);
if (this.bitArray == null) {
return 0;
}
var r = this.bitArray.Count;
long n = 0;
for (byte bit = 0; bit < r; bit++) {
if (this.bitArray[bit]) {
n |= BinaryNumber.BitAt(bit);
}
}
return n;
}
}
///
/// Gets the class structure.
///
/// Returns value.
public BinaryStructure GetClassStructure {
get {
//// Contract.Requires(this.BitArray != null);
if (this.bitArray == null) {
return null;
}
var number = this.GetNumber;
var classNumber = BinaryNumber.DetermineClassNumber(this.GSystem.Order, number);
var chs = new BinaryStructure(this.GSystem, classNumber);
return chs;
}
}
///
/// Gets StructuralCode.
///
/// Returns value.
/// Property description.
public string GetStructuralCode => this.structuralCode ?? (this.structuralCode = this.DetermineStructuralCode());
#endregion
#region Static functions
#endregion
#region Static operators
//// TICS rule 7@526: Reference types should not override the equality operator (==)
//// public static bool operator ==(BinaryStructure structure1, BinaryStructure structure2) { return object.Equals(structure1, structure2); }
//// public static bool operator !=(BinaryStructure structure1, BinaryStructure structure2) { return !object.Equals(structure1, structure2); }
//// but TICS rule 7@530: Class implements interface 'IComparable' but does not implement '==' and '!='.
///
/// Implements the operator <.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator <(BinaryStructure object1, BinaryStructure object2) {
if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) {
return object1.Number < object2.Number;
}
return false;
}
///
/// Implements the operator >.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator >(BinaryStructure object1, BinaryStructure object2) {
if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) {
return object1.Number > object2.Number;
}
return false;
}
///
/// Implements the operator <=.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator <=(BinaryStructure object1, BinaryStructure object2) {
if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) {
return object1.Number <= object2.Number;
}
return false;
}
///
/// Implements the operator >=.
///
/// The object1.
/// The object2.
///
/// Returns value.
///
public static bool operator >=(BinaryStructure object1, BinaryStructure object2) {
if (object1 != null && object2 != null && (object1.Number > 0 || object2.Number > 0)) {
return object1.Number >= object2.Number;
}
return false;
}
#endregion
#region Comparison
/// Support sorting according to level and number.
/// Object to be compared.
/// Returns value.
public override int CompareTo(object value) {
if (!(value is BinaryStructure bs)) {
return 0;
}
if (this.Level < bs.Level) {
return -1;
}
return this.Level > bs.Level ? 1 : string.Compare(this.BitArray.ToString(), bs.BitArray.ToString(), StringComparison.Ordinal);
//// This kills the DataGrid
//// throw new ArgumentException("Object is not a BinaryStructure");
}
/// Test of equality.
/// Object to be compared.
/// Returns value.
public override bool Equals(object obj) {
//// check null (this pointer is never null in C# methods)
if (object.ReferenceEquals(obj, null)) {
return false;
}
if (object.ReferenceEquals(this, obj)) {
return true;
}
if (this.GetType() != obj.GetType()) {
return false;
}
return this.CompareTo(obj) == 0;
}
/// Support of comparison.
/// Returns value.
public override int GetHashCode() {
return this.BitArray.GetHashCode();
}
#endregion
#region Public virtual methods
/// Test of emptiness.
/// Returns value.
public virtual bool IsEmptyStruct() {
return this.level == 0;
}
/// Validity test.
/// Returns value.
public virtual bool IsValidStruct() {
return true;
}
/// Evaluate properties of the structure. Used in descendant objects.
/// Must be virtual, because of call from StructuralVariety.
public virtual void DetermineBehavior() {
}
#endregion
#region Public methods
/// Makes a deep copy of the BinaryStructure object.
/// Returns object.
[JetBrains.Annotations.PureAttribute]
public override object Clone() {
return new BinaryStructure(this.GSystem, this.GetStructuralCode);
}
///
/// Determine and sets the level property.
///
/// Given bit of the structure.
/// Returns level containing the given bit.
public byte LevelOfBit(byte givenBit) {
if (givenBit == 0) {
return 0;
}
var bitLevel = -1;
//// byte order = this.GSystem.Order;
for (byte e = 0; e <= givenBit; e++) {
if (this.IsOn(e)) {
bitLevel++;
}
}
var lev = (byte)((bitLevel >= 0) ? bitLevel : 0);
return lev;
}
/// Determine and sets the level property.
public void DetermineLevel() {
this.level = this.IsOnInRange(0, (byte)(this.GSystem.Order - 1));
this.Properties[GenProperty.Level] = this.level; // used with Qualifiers
}
#endregion
#region Bit gettings
/// Gets a value indicating whether is the bit ON.
/// Element of system.
/// Returns value.
public bool IsOn(byte element)
{
return element < this.BitArray.Count && this.BitArray[element];
}
/// Gets a value indicating whether is the bit OFF.
/// Requested element.
/// Returns value.
public bool IsOff(byte element) {
if (element >= this.BitArray.Count) {
return true;
}
return !this.BitArray[element];
}
/// Returns number of bits in selected Range, that are ON.
/// First element of system.
/// Second element of system.
/// Returns value.
public byte IsOnInRange(byte elementFrom, byte elementTo) {
byte s = 0;
for (var e = elementFrom; e <= elementTo; e++) {
if (this.IsOn(e)) {
s++;
}
}
return s;
}
/// Returns number of bits in selected Range, that are OFF.
/// Fist element of system.
/// Second element of system.
/// Returns value.
public byte IsOffInRange(byte elementFrom, byte elementTo) {
byte s = 0;
for (var e = elementFrom; e <= elementTo; e++) {
if (this.IsOff(e)) {
s++;
}
}
return s;
}
#endregion
#region Bit setting
/// Sets all bits ON.
public void OnAll() {
this.BitArray.SetAll(true);
}
/// Sets selected bit ON.
/// Requested element.
public void On(byte element) {
if (element >= this.BitArray.Length) {
return;
}
this.BitArray[element] = true;
}
///
/// Sets bits in selected Range ON.
/// Fist element of system.
/// Second element of system.
public void OnRange(byte elementFrom, byte elementTo) {
for (var e = elementFrom; e <= elementTo; e++) {
this.On(e);
}
}
/// Sets all bits OFF.
public void OffAll() {
this.BitArray.SetAll(false);
}
/// Sets selected bit OFF.
/// Requested element.
public void Off(byte element) {
if (element >= this.BitArray.Length) {
return;
}
this.BitArray[element] = false;
}
/// Sets bits in selected Range OFF.
/// Fist element of system.
/// Second element of system.
public void OffRange(byte elementFrom, byte elementTo) {
for (var e = elementFrom; e <= elementTo; e++) {
this.Off(e);
}
}
#endregion
#region String representation
/// Binary schema of the structure.
/// Returns value.
public virtual string ElementString() {
var s = new StringBuilder();
//// string test = this.BitArray.ToString();
for (byte e = 0; e < this.GSystem.Order; e++) {
s.Append(this.IsOn(e) ? '1' : '0');
}
return s.ToString();
}
/// Inverse binary schema of the structure.
/// Returns value.
public string InverseElementString() {
var s = new StringBuilder();
for (int e = (byte)(this.GSystem.Order - 1); e >= 0; e--) {
s.Append(this.IsOn((byte)e) ? '1' : '0');
}
return s.ToString();
}
/// String representation of the object.
/// Returns value.
public override string ToString() {
if (this.bitArray == null) {
return string.Empty;
}
var s = new StringBuilder();
s.AppendFormat(CultureInfo.CurrentCulture, "<{0}", this.BitArray);
s.AppendFormat(CultureInfo.CurrentCulture, "L{0,2}", this.level.ToString("D", CultureInfo.CurrentCulture.NumberFormat));
s.Append(" ");
s.Append(this.ElementString());
//// s.Append(givenClassNumber); s.Append:this.tran; s.Append:this.rota;
return s.ToString();
}
#endregion
#region Structural code
/// Determine and sets the level property.
/// Structural code.
public void SetStructuralCode(string givenStructuralCode) {
this.structuralCode = givenStructuralCode;
this.bitArray = new BitArray(this.GSystem.Order);
if (string.IsNullOrWhiteSpace(this.structuralCode)) {
return;
}
var codes = this.structuralCode.Split(',');
Array.ForEach(
codes,
code => {
int element = byte.Parse(code, CultureInfo.CurrentCulture);
if (element < this.BitArray.Length) {
this.BitArray[element] = true;
}
});
}
/// Determine and sets the level property.
/// Returns value.
public string DetermineStructuralCode() {
var code = string.Empty;
if (this.level == 0) {
return code;
}
var places = this.BitPlaces;
var first = true;
foreach (var place in places) {
if (first) {
first = false;
}
else {
code += ",";
}
code += place.ToString(CultureInfo.CurrentCulture);
}
return code;
}
#endregion
#region Private methods
///
/// Sets the number.
///
/// The number.
private void SetNumber(long number) {
this.Number = number;
this.bitArray = new BitArray(this.gsystem.Order);
var bn = new BinaryNumber(this.gsystem, number);
for (byte i = 0; i < this.gsystem.Order && i < this.BitArray.Count; i++) {
this.BitArray[i] = bn.IsOn(i);
}
}
#endregion
}
}